// Copyright 2013-2015 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Serilog.Configuration;

/// <summary>
/// Controls filter configuration.
/// </summary>
public class LoggerFilterConfiguration
{
    readonly LoggerConfiguration _loggerConfiguration;
    readonly Action<ILogEventFilter> _addFilter;

    internal LoggerFilterConfiguration(
        LoggerConfiguration loggerConfiguration,
        Action<ILogEventFilter> addFilter)
    {
        _loggerConfiguration = Guard.AgainstNull(loggerConfiguration);
        _addFilter = Guard.AgainstNull(addFilter);
    }

    /// <summary>
    /// Filter out log events from the stream based on the provided filter.
    /// </summary>
    /// <param name="filters">The filters to apply.</param>
    /// <returns>Configuration object allowing method chaining.</returns>
    /// <exception cref="ArgumentNullException">When <paramref name="filters"/> is <code>null</code></exception>
    /// <exception cref="ArgumentException">When any element of <paramref name="filters"/> is <code>null</code></exception>
    public LoggerConfiguration With(params ILogEventFilter[] filters)
    {
        Guard.AgainstNull(filters);

        foreach (var logEventFilter in filters)
        {
            if (logEventFilter == null) throw new ArgumentException("Null filter is not allowed.");

            _addFilter(logEventFilter);
        }
        return _loggerConfiguration;
    }

    /// <summary>
    /// Filter out log events from the stream based on the provided filter.
    /// </summary>
    /// <typeparam name="TFilter">The filters to apply.</typeparam>
    /// <returns>Configuration object allowing method chaining.</returns>
    public LoggerConfiguration With<TFilter>()
        where TFilter : ILogEventFilter, new()
    {
        return With(new TFilter());
    }

    /// <summary>
    /// Filter out log events that match a predicate.
    /// </summary>
    /// <param name="exclusionPredicate">Function that returns true when an event
    /// should be excluded (silenced).</param>
    /// <returns>Configuration object allowing method chaining.</returns>
    public LoggerConfiguration ByExcluding(Func<LogEvent, bool> exclusionPredicate)
    {
        return With(new DelegateFilter(logEvent => !exclusionPredicate(logEvent)));
    }

    /// <summary>
    /// Filter log events to include only those that match a predicate.
    /// </summary>
    /// <param name="inclusionPredicate">Function that returns true when an event
    /// should be included (emitted).</param>
    /// <returns>Configuration object allowing method chaining.</returns>
    public LoggerConfiguration ByIncludingOnly(Func<LogEvent, bool> inclusionPredicate)
    {
        return With(new DelegateFilter(inclusionPredicate));
    }
}
